#include "AACEncodeThread.h"
#include <QDebug>

void AACEncodeThread::run() {

    qDebug() << "开始重采样";

    //  编码器
    const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_AAC);
    //  找不到编码器
    if (codec == nullptr) {
        return;
    }

    qDebug() << "找到了编码器";

    //  检查输入数据的采样格式
    // if (!this->check_sample_fmt(codec)) {
    //     qDebug() << "采样格式有问题";
    //     return;
    // }

    qDebug() << "采样格式没问题";

    //  创建编码上下文
    AVCodecContext *ctx = avcodec_alloc_context3(codec);
    if (ctx == nullptr) {
        return;
    }

    qDebug() << "创建了编码上下文";

    ctx->sample_rate = deviceInfo->sampleRate;
    ctx->sample_fmt = (AVSampleFormat)deviceInfo->format;
    ctx->ch_layout = deviceInfo->ch_layout;
    ctx->bit_rate = 48000;
    // ctx->profile = FF_PROFILE_AAC_HE_V2;

    if (avcodec_open2(ctx, codec, nullptr) < 0) {
        avcodec_free_context(&ctx);
        //  打开编码器失败
        return;
    }

    qDebug() << "编码器打开成功";

    //  存放编码前的数据
    AVFrame *frame = av_frame_alloc();
    if (frame == nullptr) {
        avcodec_free_context(&ctx);
        //  创建avframe失败
        return;
    }

    int ret = 0;

    qDebug() << "创建avframe成功";

    frame->nb_samples = ctx->frame_size;
    frame->format = ctx->sample_fmt;
    frame->ch_layout = ctx->ch_layout;

    ret = av_frame_get_buffer(frame, 0);

    if (ret < 0) {

        qDebug() << "拿到数据失败" << frame << frame->nb_samples << ctx->sample_fmt;

        avcodec_free_context(&ctx);
        av_frame_free(&frame);
        return;
    }

    qDebug() << "拿到数据成功";

    //  存放编码后的数据
    AVPacket *pkt = av_packet_alloc();
    if (pkt == nullptr) {
        avcodec_free_context(&ctx);
        av_frame_free(&frame);
        return;
    }

    qDebug() << "创建数据包成功";

    QFile inFile(this->filePath);
    if (!inFile.open(QFile::ReadOnly)) {
        avcodec_free_context(&ctx);
        av_frame_free(&frame);
        inFile.close();
        return;
    }

    qDebug() << "打开输入文件成功";

    QFile outFile(this->filePath.append(".aac"));
    if (!outFile.open(QFile::WriteOnly)) {
        avcodec_free_context(&ctx);
        av_frame_free(&frame);
        inFile.close();
        outFile.close();
        return;
    }

    qDebug() << "打开输出文件成功";

    //  读取数据
    while ((ret = inFile.read((char *)frame->data[0], frame->linesize[0])) > 0) {
        if (ret < frame->linesize[0]) {
            //  从文件中读取的数据不足以填充到frame缓冲区
            int bytes = av_get_bytes_per_sample((AVSampleFormat)frame->format);
            // av_get_channel_layout_nb_channels();
            frame->nb_samples = ret * deviceInfo->ch_layout.nb_channels / bytes;
        }

        if (this->encode(ctx, frame, pkt, outFile) < 0) {

            inFile.close();
            outFile.close();

            // 释放资源
            av_frame_free(&frame);
            av_packet_free(&pkt);
            avcodec_free_context(&ctx);

            return;
        }
    }

    qDebug() << "文件读取完毕";

    encode(ctx, nullptr, pkt, outFile);

    inFile.close();
    outFile.close();

    // 释放资源
    av_frame_free(&frame);
    av_packet_free(&pkt);
    avcodec_free_context(&ctx);

    qDebug() << "完成";

}

int AACEncodeThread::encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, QFile &outFile) {
    //  发送数据到编码器
    int ret = avcodec_send_frame(ctx,frame);
    if (ret < 0) {
        return ret;
    }

    while (true) {
        ret = avcodec_receive_packet(ctx, pkt);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
            //  继续读取数据到frame，然后发送到编码器
            return 0;
        } else if (ret < 0) {
            return ret;
        }
        //  成功从编码器拿到编码后的数据
        //  将编码后的数据写入文件
        outFile.write((char *)pkt->data, pkt->size);
        av_packet_unref(pkt);
    }

}

int AACEncodeThread::check_sample_fmt(const AVCodec *codec) {
    const enum AVSampleFormat *p = codec->sample_fmts;
    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == this->deviceInfo->format) {
            return 1;
        }
        p++;
    }
    return 0;
}
